﻿using System;
using Microsoft.Xna.Framework;

namespace Serious
{
    public struct CollisionResults
    {
        public bool intersect_z;
        public bool intersect_xy;

        public bool intersect
        {
            get
            {
                return intersect_xy && intersect_z;
            }
        }
        
        public bool floor;
        public bool ceiling;
        public bool side;
        
        public CollisionResults(bool intersect_xy, bool intersect_z, bool floor, bool ceiling, bool side)
        {
            this.intersect_xy = intersect_xy;
            this.intersect_z = intersect_z;

            this.floor = floor;
            this.ceiling = ceiling;
            this.side = side;
        }
    }

    public static class CollisionMaster
    {
        public static CollisionResults HandleCollision(ref Cylinder c, Rectangle3 r, Single a, Vector3 o, Cylinder pc, Rectangle3 pr/*, Single pa, Vector3 po*/)
        {
            CollisionResults results = new CollisionResults(false, false, false, false, false);

            Rectangle2 r2 = new Rectangle2(r.origin.AsXY(), r.size.AsXY());
            Vector2 cc2 = c.position.AsXY();
            cc2 = o.AsXY() + (cc2 - o.AsXY()).Rotated(Vector2Ext.FromDirectionDeg(-a));
            Vector2 poi = Vector2.Clamp(cc2, r2.LowLow, r2.HiHi);
            Vector2 delta = cc2 - poi;
            Single dist_sqr = delta.LengthSquared();

            results.intersect_xy = (dist_sqr < MathExt.Sqr(c.radius));
            results.intersect_z = (c.position.Z + c.half_height > r.LowZ && c.position.Z - c.half_height < r.HiZ);

            if (!results.intersect) return results;

            Single dist = MathExt.Sqrt(dist_sqr);

            Single tolerance = 0.125f;
            if (pc.position.Z - pc.half_height >= pr.HiZ-tolerance)
            {
                c.position.Z = r.HiZ + c.half_height;
                results.floor = true;
                return results;
            }
            if (pc.position.Z + pc.half_height <= pr.LowZ)
            {
                c.position.Z = r.LowZ - c.half_height;
                results.ceiling = true;
                return results;
            }

            if (dist == 0.0f)
            {
                //Logger.Log("HandleCollision(): dist == 0.0f for some reason.");

                c.position.X = pc.position.X;
                c.position.Y = pc.position.Y;
                results.side = true;

                return results;
            }

            Vector2 dir = delta / dist;
            Vector2 pos = poi + c.radius * dir;
            pos = o.AsXY() + (pos - o.AsXY()).Rotated(Vector2Ext.FromDirectionDeg(a));
            c.position.X = pos.X;
            c.position.Y = pos.Y;
            results.side = true;
            return results;
        }
    }
}
